﻿using System;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Ninject;
using Norm;
using NormActiveRecord;

namespace Kazuku.Core.Models {
	public class KazukuMvcHandler : MvcHandler, IHttpHandler {
		delegate IAsyncResult BeginInvokeDelegate(AsyncCallback callback, object state);
		delegate void EndInvokeDelegate(IAsyncResult asyncResult);
		
		protected IModelFactory Model {
			get;
			private set;
		}

		protected RequestContext RequestContext {
			get;
			private set;
		}

		private ControllerBuilder _controllerBuilder;
		protected ControllerBuilder ControllerBuilder {
			get {
				if (_controllerBuilder == null) {
					_controllerBuilder = ControllerBuilder.Current;
				}
				return _controllerBuilder;
			}
			set {
				_controllerBuilder = value;
			}
		}

		//public KazukuMvcHandler(RequestContext requestContext, IDataStore dataStore, IKernel iocContainer) : this(requestContext, new ModelFactory(dataStore, iocContainer), null) { }
		[Inject]
		public KazukuMvcHandler(RequestContext requestContext, IModelFactory modelFactory) : this(requestContext, modelFactory, null) {}

		public KazukuMvcHandler(RequestContext requestContext, IModelFactory modelFactory, IControllerFactory controllerFactory) : base(requestContext) {
			if (requestContext == null) {
				throw new ArgumentNullException("requestContext");
			}

			RequestContext = requestContext;
        	Model = modelFactory;
			if (controllerFactory != null) {
				ControllerBuilder.SetControllerFactory(controllerFactory);
			}
		}

		protected override IAsyncResult BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, object state) {
			HttpContextBase iHttpContext = new HttpContextWrapper(httpContext); 
			return BeginProcessRequest(iHttpContext, callback, state);
		}

		public IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state) {
			// Check HttpContext first for KazukuContext data
			KazukuContext current = null;
			if (httpContext.Items.Contains("KazukuContext")) {
				current = httpContext.Items["KazukuContext"] as KazukuContext;
			}
			else {
				string defaultOrgCode = "www";
				string orgCode = GetOrgCode(httpContext, defaultOrgCode);
				current = GetContextData(orgCode);
				httpContext.Items.Add("KazukuContext", current);
			}

			//if (!HttpContext.Request.IsAjaxRequest() && !Current.PageBuildingIsInProgress) {
			if (!current.PageBuildingIsInProgress) { // TODO: Consider changing name to PageDataRetrieved or somesuch
				current.PageBuildingIsInProgress = true;

				// Get the appropriate page ID that contains the module and mode being requested
				current.PageID = GetPageID(RequestContext, current);
				current.GetPageModuleFromRequest(RequestContext);
				
				// Alter the route data to point to Page controller Show action with the PageID
				RequestContext.RouteData.Values["controller"] = "page";
				RequestContext.RouteData.Values["action"] = "show";
				RequestContext.RouteData.Values["id"] = current.PageID;

				// Fall through to call the newly redirected action on the Page controller
			}

			return base.BeginProcessRequest(httpContext, callback, state);
		}

		private string GetOrgCode(HttpContextBase httpContext, string defaultOrgCode) {
			string orgCode = defaultOrgCode;
			
			// Identify the subdomain
			string[] hostNameParts = httpContext.Request.Url.Host.Split('.');
			
			if (hostNameParts.Length == 3) {
				orgCode = hostNameParts[0];
			}
			// **Only for integration testing
			else if (httpContext.Request.Url.Host == "127.0.0.1") {
				string match = "http://127.0.0.1/";
				string url = httpContext.Request.Url.ToString();
				if (url.IndexOf(match) > -1) {
					string testUrl = url.Substring(match.Length, url.Length - match.Length);
					int slashIndex = testUrl.IndexOf("/");
					if (slashIndex > -1) {
						testUrl = testUrl.Substring(0, slashIndex + 1);
					}
					string[] testHostNameParts = testUrl.Split('.');
					
					if (testHostNameParts.Length == 3) {
						orgCode = testHostNameParts[0].ToLower();
					}
				}
			}
			return orgCode;
		}

		#region IHttpHandler Members
		//bool IHttpHandler.IsReusable {
		//    get {
		//        return IsReusable;
		//    }
		//}

		//void IHttpHandler.ProcessRequest(HttpContext httpContext) {
		//    ProcessRequest(httpContext);
		//}
		#endregion

		private KazukuContext GetContextData(string orgCode) {
			return Model.Get<KazukuContext>().ByOrgCode(orgCode);
		}
		
		private ObjectId GetPageID(RequestContext requestContext, KazukuContext kazukuContext) {
			string moduleName = requestContext.RouteData.Values.ContainsKey("area") ? requestContext.RouteData.Values["area"].ToString() : string.Empty;	// Area and Module are currently synonymous.

			// Use module home page or the home page for the site
			ObjectId navID = kazukuContext.Site.ModuleHomePages.ContainsKey(moduleName) ? kazukuContext.Site.ModuleHomePages[moduleName] : kazukuContext.Site.HomePageID;
			return navID;
		}

		
	}
}
